﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Linq;
using System.Web.Script.Serialization;
using System.Net;
using System.Collections.Generic;
using System.Threading;
using System.Text.RegularExpressions;


namespace LifeInSharePoint.TwitterRollup.WebParts.TwitterRollup
{
    [ToolboxItemAttribute(false)]
    public class TwitterRollup : WebPart
    {

        private const string defaultHeaderText = "Twitter Rollup";
        private string[] accountSplit = null;
        private string currentAccount = string.Empty;

        private string headerText = defaultHeaderText;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [Category("Life In SharePoint")]
        [WebDisplayName("Header Text")]
        [Description("")]
        public string HeaderText
        {
            get { return headerText; }
            set { headerText = value; }
        }

        private const string defaultwrapperDivClass = "twitter_wrapper";
        private string wrapperDivClass = defaultwrapperDivClass;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [Category("Life In SharePoint")]
        [WebDisplayName("Wrapper Div Class")]
        [Description("")]
        public string WrapperDivClass
        {
            get { return wrapperDivClass; }
            set { wrapperDivClass = value; }
        }

        private const string defaultaccount = "";
        private string account = defaultaccount;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [Category("Life In SharePoint")]
        [WebDisplayName("Twitter Account")]
        [Description("")]
        public string Account
        {
            get { return account; }
            set { account = value; }
        }

        private const int defaultTweets = 10;
        private int tweets = defaultTweets;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [Category("Life In SharePoint")]
        [WebDisplayName("Number of Tweets to show")]
        [Description("")]
        public int Tweets
        {
            get { return tweets; }
            set { tweets = value; }
        }

        private const int defaultcacheTTL = 600;
        private int cacheTTL = defaultcacheTTL;
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [Category("Life In SharePoint")]
        [WebDisplayName("Default Cache TTL")]
        [Description("")]
        public int CacheTTL
        {
            get { return cacheTTL; }
            set { cacheTTL = value; }
        }

        static Dictionary<string, CachedData<List<Tweets>>> Cache = new Dictionary<string, CachedData<List<Tweets>>>();

        protected override void Render(HtmlTextWriter writer)
        {
            string SiteCollectionRootUrl = SPContext.Current.Site.RootWeb.Url;
            accountSplit = account.Split(',');

            
            writer.Write("<script type='text/javascript' src='" + SiteCollectionRootUrl + "/Style Library/LifeInSharePoint/Javascript/jquery-1.4.2.js'></script>");
            writer.Write("<script type='text/javascript' src='" + SiteCollectionRootUrl + "/Style Library/LifeInSharePoint/Javascript/jquery-ui-1.8.custom.min.js'></script>");
            writer.Write("<link rel='stylesheet' href='" + SiteCollectionRootUrl + "/Style Library/LifeInSharePoint/css/TwitterRollup.css' title='default' type='text/css' media='screen' />");
            writer.Write("<link rel='stylesheet' href='" + SiteCollectionRootUrl + "/Style Library/LifeInSharePoint/css/cupertino/jquery-ui-1.8.2.custom.css' title='default' type='text/css' media='screen' />");

            writer.Write("<script type='text/javascript'>");
            writer.Write("$(function() {");
            writer.Write("$('#accordion').accordion({ header: 'h3', clearStyle: true, autoHeight: false, collapsible: true});");
            writer.Write("});");
            writer.Write("</script>");

            writer.Write("<div class='" + wrapperDivClass + "' >");
            writer.Write("<div class='twitter_inner_wrapper'>");
            writer.Write("<div class='twitter_header'><h1><a href='http://www.twitter.com/" + account + "'>" + headerText + "</a></h1></div>");
            writer.Write("<div class='twitter_body'>");
                writer.Write("<div id='accordion'>");                    
            foreach (string currentAccount in accountSplit)
            {                
                writer.Write("<div>");
                    writer.Write("<h3><a href='#" + currentAccount + "'>" + currentAccount + "</a></h3>");
                    writer.Write("<div>");
                        writer.Write("<ul>");    
                        foreach (var t in GetTweets(currentAccount).Take(Tweets))
                        {
                            writer.Write("<li>");
                            string bodyText = Regex.Replace(
                                HttpUtility.HtmlEncode(t.TwitterBody),
                                @"[a-z]+://[^\s]+",
                                x => "<a href='" + x.Value.Replace("'", "&quot;") + "'>" + x.Value + "</a>",
                                RegexOptions.Compiled | RegexOptions.IgnoreCase
                                );
                            writer.Write("<div class='twitter_bodytext'>{0}</div>", bodyText);
                            writer.Write("<div class='twitter_date'>{0}</div>", t.TwitterDate.ToString());
                            writer.Write("</li>");
                        }

                        writer.Write("</ul>");
                    writer.Write("</div>");
                writer.Write("</div>");
            }

                writer.Write("</div>");//body inner
            writer.Write("</div>");//body
            writer.Write("<div class='twitter_footer'>");
            writer.Write("<img src='" + SiteCollectionRootUrl + "/Style Library/LifeInSharePoint/images/twitter_logo.png' border='0' />");
            writer.Write("</div>");//footer
            writer.Write("</div>");//inner wrapper
            writer.Write("</div>");//wrapper
        }

        public List<Tweets> GetTweets(string selectedAccount)
        {
            currentAccount = selectedAccount;
            if (!Cache.Keys.Contains(currentAccount)
                || (DateTime.Now - Cache[currentAccount].Time).TotalSeconds > CacheTTL
                )
                new Thread(Update).Start(currentAccount);

            if (!Cache.Keys.Contains(currentAccount))
                return new List<Tweets>();

            return Cache[currentAccount].Data;
        }

        public void Update(object acc)
        {
            try
            {
                string Account = (string)acc;

                var ls = new List<Tweets>();

                var jss = new JavaScriptSerializer();
                var d = jss.Deserialize<List<Dictionary<string, object>>>(
                    new WebClient()
                    .DownloadString("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + Account)
                    );

                foreach (var x in d)
                {
                    ls.Add(new Tweets()
                    {
                        TwitterBody = (string)x["text"],
                        TwitterDate = ParseDateTime((string)x["created_at"])
                    });
                }
                if (!Cache.Keys.Contains(Account))
                    Cache.Add(Account, new CachedData<List<Tweets>>());

                Cache[Account].Data = ls;
            }
            catch (Exception ex)
            {

            }
        }

        public static DateTime ParseDateTime(string date)
        {
            string dayOfWeek = date.Substring(0, 3).Trim();
            string month = date.Substring(4, 3).Trim();
            string dayInMonth = date.Substring(8, 2).Trim();
            string time = date.Substring(11, 9).Trim();
            string offset = date.Substring(20, 5).Trim();
            string year = date.Substring(25, 5).Trim();
            string dateTime = string.Format("{0}-{1}-{2} {3}", dayInMonth, month, year, time);
            DateTime ret = DateTime.Parse(dateTime);
            return ret;
        }

    }

    public class Tweets
    {
        public DateTime TwitterDate { get; set; }
        public string TwitterBody { get; set; }
    }

    class CachedData<T>
    {
        public DateTime Time { get; private set; }

        T data;
        public T Data
        {
            get
            {
                return data;
            }
            set
            {
                Time = DateTime.Now;
                data = value;
            }
        }
    }
}
